package cn.com.headfree.salary.service.impl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.com.headfree.entity.TSalaryInfo;
import cn.com.headfree.salary.service.IPointcalculateService;
import cn.com.headfree.util.SimpleThreadPool;
import cn.com.headfree.vo.DealFileVo;
import com.gta.edu.sdk.util.IdGen;
import com.gta.edu.sdk.util.StringUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.gta.edu.sdk.common.dto.Page;
import cn.com.headfree.callback.call.FileServerCall;
import cn.com.headfree.entity.isc.User;
import cn.com.headfree.salary.dao.SalaryDao;
import cn.com.headfree.salary.service.SalaryService;
import cn.com.headfree.salary.service.IUserDataInfoService;
import cn.com.headfree.util.ZipGenerateUtils;
import cn.com.headfree.vo.BusinessIdsVo;
import feign.Response;

@Service("salaryService")
public class SalaryServiceImpl implements SalaryService {
	private static final Logger LOG = LogManager.getLogger(SalaryServiceImpl.class);

	@Autowired
	private SalaryDao salaryDao;
	@Autowired
	private FileServerCall fileServerCall;
	@Autowired
	private IUserDataInfoService userDataInfoService;
	@Autowired
	private IPointcalculateService pointcalculateService;
	private static final Logger log = LogManager.getLogger(SalaryServiceImpl.class);

	@Value("${file_path}")
	private String file_path;
	// 临时下载路径
	@Value("${file_temp_path}")
	private String file_temp_path;

	@Override
	public void getPageSalaryInfo(Page<TSalaryInfo> page, String year, User user) {
		salaryDao.getPageSalaryInfo(page, year, user);
	}

	@Override
	public void saveSalaryInfo(TSalaryInfo salaryInfo) {
		salaryInfo.setCreaterId(salaryInfo.getErpNo());
		salaryInfo.setCreaterName(salaryInfo.getUserName());
		salaryInfo.setUpdaterId(salaryInfo.getErpNo());
		salaryInfo.setUpdaterName(salaryInfo.getUserName());
		salaryInfo.setCreateTime(new Date());
		salaryInfo.setUpdateTime(new Date());
		salaryInfo.setDelSign(0);
		salaryInfo.setAuditStatus("0");//待审核
//		TOrgDept dept = salaryDao.getOrgNameByOrgId(salaryInfo.getOrgId());
//		if (dept != null) {
//			salaryInfo.setOrgName(dept.getName());
//		}
		salaryDao.saveSalaryInfo(salaryInfo);
	}


	@Override
	public void downloadFiles(String erpNo,String sysCode, String businessNode, HttpServletRequest request,
							  HttpServletResponse response,String salaryId,int year) {
		InputStream inputStream = null;
		try {
//			JSONArray jsonArray = null;
//			JSONObject obj = null;
			String fileId = null;
			String fileName = null;
			String dirName = null;
			List<BusinessIdsVo> list= userDataInfoService.getBusinessIdByErpNo(erpNo,salaryId,year);
			for (BusinessIdsVo bvo : list) {
				String businessId=bvo.getBusinessId();
				if(!StringUtil.isNullOrEmpty(businessId)) {
					List<DealFileVo> lists=salaryDao.getFilesByBusinessId(businessId,businessNode);
					for(DealFileVo f:lists) {
//						ResultData resultData = fileServerCall.findFileList(sysCode, f.get, businessNode);
//						if (null != resultData) {
//							log.info("获取附件数据为--" + resultData.toString());
						File file = new File(file_temp_path);
						if (!file.exists()) {
							file.mkdirs();
						}
//							if (null != resultData.getData()) {
//								jsonArray = JSONArray.fromObject(resultData.getData());
//								if ((null != jsonArray) && (0 < jsonArray.size())) {
//									for (int i = 0; i < jsonArray.size(); i++) {
//										obj = (JSONObject) jsonArray.get(i);
//										if (null != obj) {


						fileId = f.getFileId();
						fileName = f.getFileName();
						dirName = bvo.getTypeName();
						// 下载文件
						if (fileId != null) {
							try {
								Response resp = fileServerCall.downloadFile(fileId);
								// 判断是否下载成功
								if (resp.status() == 200) {
									Response.Body body = resp.body();
									inputStream = body.asInputStream();
									downloadSingleFile(inputStream, fileName, dirName);
								}
							} catch (Exception e) {
								log.error("下载文件失败！", e);
							}
						}
//										}
//									}
//								}
//							}
//						}
					}
				}

			}
			File f = new File(file_temp_path);
			File files[] = f.listFiles();
//	        downLoadAllFiles(files,request,response);
			ZipGenerateUtils.createZip(request, response, file_temp_path, "附件.rar");
			ZipGenerateUtils.ZipFiles(request, response, files, "附件.rar");
			deleteDirectory(file_temp_path);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 删除目录（文件夹）以及目录下的文件
	 *
	 * @param sPath 被删除目录的文件路径
	 * @return 目录删除成功返回true，否则返回false
	 */
	public boolean deleteDirectory(String sPath) {
		// 如果sPath不以文件分隔符结尾，自动添加文件分隔符
		if (!sPath.endsWith(File.separator)) {
			sPath = sPath + File.separator;
		}
		File dirFile = new File(sPath);
		// 如果dir对应的文件不存在，或者不是一个目录，则退出
		if (!dirFile.exists() || !dirFile.isDirectory()) {
			return false;
		}
		boolean flag = true;
		// 删除文件夹下的所有文件(包括子目录)
		File[] files = dirFile.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 删除子文件
			if (files[i].isFile()) {
				flag = deleteFile(files[i].getAbsolutePath());
				if (!flag)
					break;
			} // 删除子目录
			else {
				flag = deleteDirectory(files[i].getAbsolutePath());
				if (!flag)
					break;
			}
		}
		if (!flag)
			return false;
		// 删除当前目录
		if (dirFile.delete()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 删除单个文件
	 *
	 * @param sPath 被删除文件的文件名
	 * @return 单个文件删除成功返回true，否则返回false
	 */
	public boolean deleteFile(String sPath) {
		boolean flag = false;
		File file = new File(sPath);
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {
			file.delete();
			flag = true;
		}
		return flag;
	}

	/**
	 * 创建zip文件
	 *
	 * @param file       文件或者目录
	 * @param parentPath 父路径（默认为""）
	 * @param zos        ZipOutputStream
	 */
	private static void writeZip(File file, String parentPath, ZipOutputStream zos) {
		if (file.exists()) {
			if (file.isDirectory()) {// 处理文件夹
				parentPath += file.getName() + File.separator;
				File[] files = file.listFiles();
				if (files.length != 0) {
					for (File f : files) {
						writeZip(f, parentPath, zos);
					}
				} else {// 空目录则创建当前目录
					try {
						zos.putNextEntry(new ZipEntry(parentPath));
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			} else {
				FileInputStream fis = null;
				try {
					fis = new FileInputStream(file);
					ZipEntry ze = new ZipEntry(parentPath + file.getName());
					zos.putNextEntry(ze);
					byte[] content = new byte[1024];
					int len;
					while ((len = fis.read(content)) != -1) {
						zos.write(content, 0, len);
						zos.flush();
					}

				} catch (FileNotFoundException e) {
					System.out.println("创建ZIP文件失败");
				} catch (IOException e) {
					System.out.println("创建ZIP文件失败");
				} finally {
					try {
						if (fis != null) {
							fis.close();
						}
					} catch (IOException e) {
						System.out.println("创建ZIP文件失败");
					}
				}
			}
		}
	}

	private String downloadSingleFile(InputStream inputStream, String fileName, String dirName) {
		FileOutputStream fileOut = null;
		BufferedInputStream bis = new BufferedInputStream(inputStream);
		// 判断文件的保存路径后面是否以/结尾
		if (!file_temp_path.endsWith("/")) {
			file_temp_path += "/";
		}
		if (!dirName.endsWith("/")) {
			dirName += "/";
		}
		File f = new File(file_temp_path + dirName);
		if (!f.exists()) {
			f.mkdirs();
		}
		// 写入到文件（注意文件保存路径的后面一定要加上文件的名称）
		try {
			fileOut = new FileOutputStream(file_temp_path + dirName + fileName);
			BufferedOutputStream bos = new BufferedOutputStream(fileOut);
			byte[] buf = new byte[4096];
			int length = bis.read(buf);
			// 保存文件
			while (length != -1) {
				bos.write(buf, 0, length);
				length = bis.read(buf);
			}
			bos.close();
			bis.close();
			return null;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	// 文件打包下载
	public HttpServletResponse downLoadAllFiles(File[] files, HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
			/**
			 * 这个集合就是你想要打包的所有文件， 这里假设已经准备好了所要打包的文件
			 */
			// List<File> files = new ArrayList<File>();

			/**
			 * 创建一个临时压缩文件， 我们会把文件流全部注入到这个文件中 这里的文件你可以自定义是.rar还是.zip
			 */
			File file = new File(file_path + "/附件.rar");
			if (!file.exists()) {
				file.createNewFile();
			}
			response.reset();
			// response.getWriter()
			// 创建文件输出流
			FileOutputStream fous = new FileOutputStream(file);
			/**
			 * 打包的方法我们会用到ZipOutputStream这样一个输出流, 所以这里我们把输出流转换一下
			 */
			ZipOutputStream zipOut = new ZipOutputStream(fous);
			/**
			 * 这个方法接受的就是一个所要打包文件的集合， 还有一个ZipOutputStream
			 */
			zipFile(files, zipOut);
			zipOut.close();
			fous.close();
			downloadZip(file, response);
		} catch (Exception e) {
			e.printStackTrace();
		}
		/**
		 * 直到文件的打包已经成功了， 文件的打包过程被我封装在FileUtil.zipFile这个静态方法中， 稍后会呈现出来，接下来的就是往客户端写数据了
		 */
		return null;
	}

	/**
	 * 把接受的全部文件打成压缩包
	 */
	public void zipFile(File[] files, ZipOutputStream outputStream) {
		int size = files.length;
		for (int i = 0; i < size; i++) {
			File file = (File) files[i];
			zipFile(file, outputStream);
		}
	}

	public HttpServletResponse downloadZip(File file, HttpServletResponse response) {
		try {
			// 以流的形式下载文件。
			InputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
			byte[] buffer = new byte[fis.available()];
			fis.read(buffer);
			fis.close();
			// 清空response
			response.reset();

			OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
			response.setContentType("application/octet-stream");

//如果输出的是中文名的文件，在此处就要用URLEncoder.encode方法进行处理
			response.setHeader("Content-Disposition",
					"attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
			toClient.write(buffer);
			toClient.flush();
			toClient.close();
//        File f=new File(file_temp_path);
//        f.deleteOnExit();
			return null;
		} catch (IOException ex) {
			ex.printStackTrace();
		} finally {
			try {
				File f = new File(file.getPath());
				f.delete();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 根据输入的文件与输出流对文件进行打包
	 */
	public void zipFile(File inputFile, ZipOutputStream ouputStream) {
		try {
			if (inputFile.exists()) {
				/**
				 * 如果是目录的话这里是不采取操作的， 至于目录的打包正在研究中
				 */
				if (inputFile.isFile()) {
					FileInputStream IN = new FileInputStream(inputFile);
					BufferedInputStream bins = new BufferedInputStream(IN, 512);
					// org.apache.tools.zip.ZipEntry
					ZipEntry entry = new ZipEntry(inputFile.getName());
					ouputStream.putNextEntry(entry);
					// 向压缩文件中输出数据
					int nNumber;
					byte[] buffer = new byte[512];
					while ((nNumber = bins.read(buffer)) != -1) {
						ouputStream.write(buffer, 0, nNumber);
					}
					// 关闭创建的流对象
					bins.close();
					IN.close();
				} else {
					try {
						File[] files = inputFile.listFiles();
						for (int i = 0; i < files.length; i++) {
							zipFile(files[i], ouputStream);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public List<TSalaryInfo> judge(TSalaryInfo salaryInfo) {
		return salaryDao.judge(salaryInfo);
	}

	@Override
	public TSalaryInfo selectTSalaryInfoById(String id){
		return salaryDao.selectTSalaryInfoById(id);
	}

	@Override
	public void saveAllSalaryInfo(Integer year,User user,String ruleId){
		List<User> useList = salaryDao.searchUserListByOrgId(user.getBaseOrgId());
		if(CollectionUtils.isNotEmpty(useList)){
			useList.stream().forEach(item ->{
				TSalaryInfo tSalaryInfo = new TSalaryInfo();
				tSalaryInfo.setId(IdGen.uuid());
				tSalaryInfo.setYear(year);
				tSalaryInfo.setRuleId(ruleId);
				tSalaryInfo.setErpNo(item.getFax());
				tSalaryInfo.setUserName(item.getName());
				tSalaryInfo.setOrgId(item.getBaseOrgId());
				tSalaryInfo.setOrgName(item.getBaseOrgName());
				tSalaryInfo.setCreaterId(user.getFax());
				tSalaryInfo.setCreaterName(user.getName());
				tSalaryInfo.setUpdaterId(user.getFax());
				tSalaryInfo.setUpdaterName(user.getName());
				tSalaryInfo.setCreateTime(new Date());
				tSalaryInfo.setUpdateTime(new Date());
				tSalaryInfo.setDelSign(0);
				tSalaryInfo.setAuditStatus("0");//待审核
				List<TSalaryInfo> salaryInfos = judge(tSalaryInfo);
				if(CollectionUtils.isEmpty(salaryInfos)){
					salaryDao.saveSalaryInfo(tSalaryInfo);
				}
			});
		}
		LOG.info("薪档调整一键全员申报<<{},{}年份>> -> 职称申报支撑主表（t_salary_info）内容，添加完成！",user.getBaseOrgName(),year);
		//开线程(单线程) 补充个人积分明细信息
		new SimpleThreadPool().execute(new ExamineParsingThread(user,year));
	}


	private class ExamineParsingThread implements Runnable {

		private User user;
		private Integer year;

		public ExamineParsingThread(User user,Integer year) {
			this.user = user;
			this.year = year;
		}

		@Override
		public void run() {
			try {
				Singleton.getInstance().instailDetai(salaryDao, pointcalculateService,user,year);
				LOG.info("薪档调整一键全员申报 <<{},{}年份 >> -> 年度个人积分明细添加成功",user.getBaseOrgName(),year);
			}catch (Exception e){
				LOG.error("薪档调整一键全员申报 年份 -> 年度个人积分明细 提报异常 {}",e);
			}
		}
	}

	public void getPageSalaryInfoQuery(Page<TSalaryInfo> page,String baseOrgId, String userName, String erpNo, Integer year, String auditStatus){
		salaryDao.getPageSalaryInfoQuery(page,baseOrgId,userName,erpNo,year,auditStatus);
	}

	public List<TSalaryInfo> getListSalaryInfoQuery(String baseOrgId, String userName, String erpNo, Integer year, String auditStatus){
		return salaryDao.getListSalaryInfoQuery(baseOrgId,userName,erpNo,year,auditStatus);
	}

	@Override
	public void saveSalaryInfoByErpNo(User user,Integer year,String erpNo,String ruleId,String orgId) throws ParseException {
		List<User> useList = salaryDao.searchUserByErpNo(orgId,erpNo);
		if(CollectionUtils.isNotEmpty(useList)){
			User item = useList.get(0);
			TSalaryInfo tSalaryInfo = new TSalaryInfo();
			tSalaryInfo.setId(IdGen.uuid());
			tSalaryInfo.setYear(year);
			tSalaryInfo.setRuleId(ruleId);
			tSalaryInfo.setErpNo(item.getFax());
			tSalaryInfo.setUserName(item.getName());
			tSalaryInfo.setOrgId(item.getBaseOrgId());
			tSalaryInfo.setOrgName(item.getBaseOrgName());
			tSalaryInfo.setCreaterId(user.getFax());
			tSalaryInfo.setCreaterName(user.getName());
			tSalaryInfo.setUpdaterId(user.getFax());
			tSalaryInfo.setUpdaterName(user.getName());
			tSalaryInfo.setCreateTime(new Date());
			tSalaryInfo.setUpdateTime(new Date());
			tSalaryInfo.setDelSign(0);
			tSalaryInfo.setAuditStatus("0");//待审核
			List<TSalaryInfo> salaryInfos = judge(tSalaryInfo);
			if(CollectionUtils.isEmpty(salaryInfos)){
				salaryDao.saveSalaryInfo(tSalaryInfo);
			}else{
				tSalaryInfo.setId(salaryInfos.get(0).getId());
			}
			//积分明细表数据添加
			pointcalculateService.saveSalaryPointDeatail(user, tSalaryInfo);

		}else{
			LOG.error("用户查询数据为空 ，orgId:{},ERP:{},薪档申报失败！");
		}
	}

}
